package com.life.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JPanel;

import com.life.model.IModelEventsListener;
import com.life.model.LifeModel;
import com.life.model.event.ModelBoardCompleteEvent;
import com.life.model.event.ModelBoardCreateEvent;
import com.life.model.event.ModelBoardResetEvent;
import com.life.model.event.ModelBoardRuleSetEvent;
import com.life.model.event.ModelBoardUpdateEvent;
import com.life.utils.BoardLocationStruct;

public class LifeCanvas extends JPanel implements IModelEventsListener,
	MouseListener, MouseMotionListener
{

    protected LifeModel theModel = null;

    protected boolean initialized = false;

    int pixelWidth = 0;

    int pixelHeight = 0;

    int width = 0;

    int height = 0;

    int cellWidth = 0;

    int cellHeight = 0;
    
    public LifeCanvas(LifeModel model)
    {
	theModel = model;
	initialized = true;
	model.addModelEventsListener(this);
	this.addMouseMotionListener(this);
	this.addMouseListener(this);
    }

    public void modelBoardCompleted(ModelBoardCompleteEvent event)
    {
	// TODO Auto-generated method stub

    }

    public void modelBoardCreated(ModelBoardCreateEvent event)
    {
	// TODO Auto-generated method stub
	theModel = event.getModel();
	initialized = true;
	repaint();
    }

    public void modelBoardUpdated(ModelBoardUpdateEvent event)
    {
	initialized = true;
	theModel = event.getModel();
	repaint();
    }

    public Color getNeighborColor(int value)
    {
	return ColorGenerator.getInstance().getNeighborColor(value);
    }

    @Override
    public void paint(Graphics g)
    {
	super.paint(g);
	if (initialized)
	{
	    Dimension dim = theModel.getSize();
	    width = (int) dim.getWidth();
	    height = (int) dim.getHeight();

	    pixelWidth = (int) this.getWidth();
	    pixelHeight = (int) this.getHeight();

	    Image image = this.getDoubleBufferedImage();
	    Graphics doubleBuf = image.getGraphics();

	    cellWidth = pixelWidth / width+1;
	    cellHeight = pixelHeight / height+1;

	    doubleBuf.setColor(ColorGenerator.getBackgroundColor());
	    doubleBuf.fillRect(0, 0, pixelWidth, pixelHeight);

	    doubleBuf.setColor(java.awt.Color.black);

	    for (int i = 0; i < width; i++)
	    {
		for (int j = 0; j < height; j++)
		{
		    if (theModel.isAlive(i, j))
		    {
			int neighbors = theModel.getNeighborCount(i, j);
			Color color = getNeighborColor(neighbors);
			drawAlive(i, j, doubleBuf, color);
		    }
		    else
		    {
			doubleBuf.setColor(java.awt.Color.DARK_GRAY);
			doubleBuf.drawRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
			
		    }
		}
	    }
	    flushBuffer(image,g);
	}
    }
    
    public void drawAlive(int i, int j, Color color)
    {
	Graphics g = this.getGraphics();
	Color newColor = new Color(Math.max(0,color.getRed()-50),
		Math.max(0,color.getGreen()-50),
		Math.max(0,color.getBlue()-50),
		color.getAlpha());
	g.setColor(newColor);
	g.fillRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
	g.setColor(color);
	g.fillRect(i * cellWidth + 1, j * cellHeight + 1, cellWidth - 2,
		cellHeight - 2);
	
    }
    
    public void drawAlive(int i, int j)
    {
	drawAlive(i,j,
		this.getGraphics(),this.getNeighborColor(theModel.getNeighborCount(i,j)));
    }
  
    
    public void drawAlive(int i, int j, Graphics g, Color color)
    {
	Color newColor = new Color(color.getRed(), color.getGreen(), color
		.getBlue(), 150);
	g.setColor(color);
	g.fillRect(i * cellWidth + 1, j * cellHeight + 1, cellWidth - 2,
		cellHeight - 2);
	g.setColor(newColor);
	g.fillRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);

    }
    
    public void drawDead(int i, int j, Graphics g, Color color)
    {
	g.setColor(ColorGenerator.getInstance().getBackgroundColor());
	g.fillRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
	g.setColor(java.awt.Color.DARK_GRAY);
	g.drawRect(i * cellWidth, j * cellHeight, cellWidth, cellHeight);
    }

    public void mouseReleased(MouseEvent arg0)
    {
	// TODO Auto-generated method stub

    }
    boolean erase = false;
   
    public void mouseDragged(MouseEvent arg0)
    {
	System.out.println(arg0.getButton());
	if(!erase)
	{
	
	int i = arg0.getX() / cellWidth;
	int j = arg0.getY() / cellHeight;

	int buffer = 0;

	for (int x = -buffer; x <= buffer; x++)
	{
	    for (int y = -buffer; y <= buffer; y++)
	    {
		// Check if the cell is valid meaning we're not off the board.
		if (theModel.isValid(i + x, j + y))
		{
		    if (!theModel.isAlive(i + x, j + y))
		    {
			theModel.setAlive(i + x, j + y);
		    }
		}
	    }
	}

	for (int x = -buffer; x <= buffer; x++)
	{
	    for (int y = -buffer; y <= buffer; y++)
	    {
		// Check if the cell is valid meaning we're not off the board.
		if (theModel.isValid(i + x, j + y))
		{
		    drawAlive(i + x, y + j, getGraphics(), getNeighborColor(theModel.getNeighborCount(i + x,
				    j + y)));
		}
	    }
	}
	}
	else if(erase)
	{
	    int i = arg0.getX() / cellWidth;
		int j = arg0.getY() / cellHeight;

		int buffer = 0;

		for (int x = -buffer; x <= buffer; x++)
		{
		    for (int y = -buffer; y <= buffer; y++)
		    {
			// Check if the cell is valid meaning we're not off the board.
			if (theModel.isValid(i + x, j + y))
			{
			    if (theModel.isAlive(i + x, j + y))
			    {
				theModel.setDead(i + x, j + y);
			    }
			}
		    }
		}

		for (int x = -buffer; x <= buffer; x++)
		{
		    for (int y = -buffer; y <= buffer; y++)
		    {
			// Check if the cell is valid meaning we're not off the board.
			if (theModel.isValid(i + x, j + y))
			{
			    drawDead(i + x, y + j, getGraphics(), getNeighborColor(theModel.getNeighborCount(i + x,
					    j + y)));
			}
		    }
		}
	}
		
    }

    public void mouseMoved(MouseEvent arg0)
    {
	// TODO Auto-generated method stub

    }

    public void mouseClicked(MouseEvent arg0)
    {
	// mouseDragged(arg0);

    }

    public void mouseEntered(MouseEvent e)
    {
	// TODO Auto-generated method stub

    }

    public void mouseExited(MouseEvent e)
    {
	// TODO Auto-generated method stub

    }

    public void mousePressed(MouseEvent e)
    {
	if(e.getButton() == MouseEvent.BUTTON1)
	{
	    erase = false;
	    mouseDragged(e);
	}
	else if(e.getButton() == MouseEvent.BUTTON3)
	{
	   erase = true;  
	   mouseDragged(e);
	}
	

    }

    public void modelRuleSet(ModelBoardRuleSetEvent event)
    {

    }

    public void modelBoardReset(ModelBoardResetEvent event)
    {

    }

    public BoardLocationStruct getBoardLocation(int mapX, int mapY)
    {
	BoardLocationStruct returnVal = new BoardLocationStruct();
	returnVal.boardX = mapX	/ cellWidth;
	returnVal.boardY = mapY / cellHeight;
	
	return returnVal;
    }

    public LifeModel getModel()
    {
	// TODO Auto-generated method stub
	return theModel;
    }

    public Image getDoubleBufferedImage()
    {
	return this.createImage(pixelWidth, pixelHeight);
    }
    
    public void flushBuffer(Image image, Graphics g)
    {
          g.drawImage(image, 0, 0, null);
    }
    
    public void flushBuffer(Image image)
    {
	flushBuffer(image, this.getGraphics());
    }
    
}
